﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using CoreEx.Database.Client;
using CoreEx.Database.Query.Expressions;
using LinFu.IoC.Interfaces;
using LinFu.IoC;
using CoreEx.Common.Extensions;
namespace CoreEx.Database.Query
{
    public static class CommandExtensions
    {
        private static IServiceContainer _serviceContainer = Services.ServiceLocator.Container;

        public static IDataReader ExecuteReader(this IDbCommand dbCommand, IQueryExpression queryExpression)
        {
            string connectionName = ((INamedConnection) dbCommand.Connection).Name;
            string providerName = _serviceContainer.GetService<DbConnectionInfo>(connectionName).ProviderName;            
            var queryTranslator = _serviceContainer.GetService<IQueryTranslator>(providerName);
            ITranslatedQuery translatedQuery = queryTranslator.Translate(queryExpression);
            dbCommand.CommandType = CommandType.Text;
            dbCommand.CommandText = translatedQuery.Sql;
            translatedQuery.ImplicitParameters.ForEach(p => dbCommand.Parameters.Add(p.Value));            
            return dbCommand.ExecuteReader(CommandBehavior.Default);
        }

        public static IDataReader ExecuteReader(this IDbCommand dbCommand, IQueryExpression queryExpression, CommandBehavior commandBehavior)
        {
            string connectionName = ((INamedConnection)dbCommand.Connection).Name;
            string providerName = _serviceContainer.GetService<DbConnectionInfo>(connectionName).ProviderName;
            var queryTranslator = _serviceContainer.GetService<IQueryTranslator>(providerName);
            ITranslatedQuery translatedQuery = queryTranslator.Translate(queryExpression);
            dbCommand.CommandType = CommandType.Text;
            dbCommand.CommandText = translatedQuery.Sql;
            translatedQuery.ImplicitParameters.ForEach(p => dbCommand.Parameters.Add(p.Value));
            return dbCommand.ExecuteReader(commandBehavior);
        }

        /// <summary>
        /// Translates the <see cref="DbQueryExpression"/> and executes the query. 
        /// </summary>
        /// <param name="dbCommand">The <see cref="IDbCommand"/> used to execute the query.</param>
        /// <param name="queryExpression">The <see cref="DbQueryExpression"/> that represents the query to execute.</param>
        /// <returns><see cref="IDataReader"/></returns>
        public static IDataReader ExecuteReader(this IDbCommand dbCommand, DbQueryExpression queryExpression)
        {
            string connectionName = ((INamedConnection)dbCommand.Connection).Name;
            string providerName = _serviceContainer.GetService<DbConnectionInfo>(connectionName).ProviderName;
            var queryTranslator = DbProviderFactories.GetFactory(providerName).CreateQueryTranslator();
            var translateResult = queryTranslator.Translate(queryExpression);
            dbCommand.CommandText = translateResult.Sql;
            dbCommand.CommandType = CommandType.Text;
            translateResult.Parameters.ForEach(p => dbCommand.Parameters.Add(p));
            return dbCommand.ExecuteReader(CommandBehavior.CloseConnection);
        }

        /// <summary>
        /// Translates the <see cref="DbQueryExpression"/> and executes the query. 
        /// </summary>
        /// <param name="dbCommand">The <see cref="IDbCommand"/> used to execute the query.</param>
        /// <param name="queryExpression">The <see cref="DbQueryExpression"/> that represents the query to execute.</param>
        /// <returns><see cref="int"/></returns>
        public static int ExecuteNonQuery(this IDbCommand dbCommand, DbExpression queryExpression)
        {
            string connectionName = ((INamedConnection)dbCommand.Connection).Name;
            string providerName = _serviceContainer.GetService<DbConnectionInfo>(connectionName).ProviderName;
            var queryTranslator = DbProviderFactories.GetFactory(providerName).CreateQueryTranslator();
            var translateResult = queryTranslator.Translate(queryExpression);
            dbCommand.Parameters.Clear();
            dbCommand.CommandText = translateResult.Sql;
            dbCommand.CommandType = CommandType.Text;
            translateResult.Parameters.ForEach(p => dbCommand.Parameters.Add(p));
            return dbCommand.ExecuteNonQuery();
        }


    }
}
